import { $set } from '@feng3d/serialization';
import { BufferGeometry3D, Color, LineBasicMaterial3D, MeshBasicMaterial3D, Node3D, Path, PerspectiveCamera3D, Scene3D, ShapeGeometry3D, WebGLRenderer3D } from 'feng3d-three';
import '../../extension/controls/OrbitControls3D';
import { FontLoader3D } from '../../extension/loaders/FontLoader3D';

const rootPath = '../../';

let camera: PerspectiveCamera3D;
let scene: Scene3D;
let renderer: WebGLRenderer3D;

init();

function init()
{
    camera = new Node3D().addComponent('PerspectiveCamera3D', { fov: 45, aspect: window.innerWidth / window.innerHeight, near: 1, far: 10000 });
    camera.entity.position.set(0, -400, 600);

    scene = new Node3D().addComponent('Scene3D');
    scene.background = new Color(0xf0f0f0);

    const loader = new FontLoader3D();
    loader.load(`${rootPath}fonts/helvetiker_regular.typeface.json`, function (font)
    {
        const color = 0x006699;

        const matDark = $set(new LineBasicMaterial3D(), {
            color: { value: color },
            side: 'DoubleSide'
        });

        const matLite = $set(new MeshBasicMaterial3D(), {
            color: { value: color },
            transparent: true,
            opacity: 0.4,
            side: 'DoubleSide'
        });

        const message = '   Three.js\nSimple text.';

        const shapes = font.generateShapes(message, 100);

        const geometry = $set(new ShapeGeometry3D(), { shapes });

        geometry.computeBoundingBox();

        const xMid = -0.5 * (geometry.boundingBox.max.x - geometry.boundingBox.min.x);

        geometry.translate(xMid, 0, 0);

        // make shape ( N.B. edge view not visible )

        const text = new Node3D().addComponent('Mesh3D', { geometry, material: matLite });
        text.entity.position.z = -150;
        scene.entity.addChild(text.entity);

        // make line shape ( N.B. edge view remains visible )

        const holeShapes: Path[] = [];

        for (let i = 0; i < shapes.length; i++)
        {
            const shape = shapes[i];

            if (shape.holes && shape.holes.length > 0)
            {
                for (let j = 0; j < shape.holes.length; j++)
                {
                    const hole = shape.holes[j];
                    holeShapes.push(hole);
                }
            }
        }

        // eslint-disable-next-line prefer-spread
        shapes.push.apply(shapes, holeShapes);

        const lineText = new Node3D();

        for (let i = 0; i < shapes.length; i++)
        {
            const shape = shapes[i];

            const points = shape.getPoints();
            const geometry = new BufferGeometry3D().setFromPoints(points);

            geometry.translate(xMid, 0, 0);

            const lineMesh = new Node3D().addComponent('Line3D', { geometry, material: matDark });
            lineText.addChild(lineMesh.entity);
        }

        scene.entity.addChild(lineText);

        render();
    }); // end load function

    renderer = scene.addComponent('WebGLRenderer3D', { parameters: { antialias: true } });
    renderer.setPixelRatio(window.devicePixelRatio);
    renderer.setSize(window.innerWidth, window.innerHeight);
    document.body.appendChild(renderer.domElement);

    const controls = new Node3D().addComponent('OrbitControls3D', { camera, domElement: renderer.domElement });
    controls.target.set(0, 0, 0);
    controls.update();

    controls.emitter.on('change', render);

    window.addEventListener('resize', onWindowResize);
} // end init

function onWindowResize()
{
    camera.aspect = window.innerWidth / window.innerHeight;
    camera.updateProjectionMatrix();

    renderer.setSize(window.innerWidth, window.innerHeight);

    render();
}

function render()
{
    renderer.render(scene, camera);
}
